#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : notification_service.py
@DESCRIPTION   : 通知服务，用于发送SSE消息
'''
import threading
import queue
import time
from app.middlewares.sse import MemorySSE  # 替换为内存版SSE
from flask import current_app, g

class NotificationService:
    """通知服务类，用于发送SSE消息"""

    # 创建类级别的任务队列和工作线程
    _task_queue = queue.Queue()
    _worker_thread = None
    _is_worker_running = False
    _worker_lock = threading.Lock()

    def __init__(self):
        pass

    @classmethod
    def _ensure_worker_running(cls):
        """确保工作线程正在运行"""
        with cls._worker_lock:
            if not cls._is_worker_running:
                cls._is_worker_running = True
                cls._worker_thread = threading.Thread(target=cls._process_notification_queue)
                cls._worker_thread.daemon = True  # 设为守护线程，不阻止程序退出
                cls._worker_thread.start()
                current_app.logger.info("通知工作线程已启动")
    
    @classmethod
    def _process_notification_queue(cls):
        """处理通知队列中的任务"""
        try:
            while True:
                try:
                    # 获取任务，设置超时以便线程可以周期性检查是否应该退出
                    task = cls._task_queue.get(timeout=5)
                    
                    if task is None:  # None作为退出信号
                        break
                        
                    # 执行发送任务
                    channel, payload, notification_type = task
                    
                    result = MemorySSE.publish(
                        message=payload,
                        type=notification_type,
                        channel=channel
                    )
                    
                    # 标记任务完成
                    cls._task_queue.task_done()
                    
                    # 记录结果
                    if result:
                        current_app.logger.debug(f"成功发送通知到通道: {channel}")
                    else:
                        current_app.logger.warning(f"通知发送失败，通道可能不存在: {channel}")
                        
                except queue.Empty:
                    # 队列为空，继续等待
                    continue
                except Exception as e:
                    current_app.logger.error(f"处理通知任务时出错: {str(e)}")
                    # 标记任务完成，即使失败
                    try:
                        cls._task_queue.task_done()
                    except:
                        pass
        finally:
            # 设置工作线程状态为未运行
            with cls._worker_lock:
                cls._is_worker_running = False
                current_app.logger.info("通知工作线程已退出")

    @staticmethod
    def send_user_notification(user_id, message, notification_type='system', data=None, level='info'):
        """
        向指定用户发送通知, 核心原理实际上是将消息加入到通道的用户消息队列中。
        
        Args:
            user_id: 用户ID
            message: 通知消息内容
            notification_type: 通知类型, 例如：system, chat, profile_updated
            data: 附加数据
            level: 通知级别 (info, success, warning, error)
        
        Returns:
            bool: 发送结果
        """
        try:
            payload = {
                "message": message,
                "type": notification_type,
                "level": level
            }
            
            if data:
                payload["data"] = data
                
            result = MemorySSE.publish(
                message=payload,
                type=notification_type,
                channel=f'user.{user_id}'
            )
            
            if result:
                current_app.logger.info(f"已向用户 {user_id} 发送 {notification_type} 类型通知")
            else:
                current_app.logger.warning(f"用户 {user_id} 没有活跃连接，通知未发送")
                
            return result
        except Exception as e:
            current_app.logger.error(f"发送通知失败: {str(e)}")
            return False
    
    @staticmethod
    def send_user_sse(user_id, profile_data, type='profile_updated'):
        """
        发送个人资料更新通知
        
        Args:
            user_id: 用户ID
            profile_data: 更新的个人资料数据
            notification_type: 通知类型, 事先设计好的业务类型名称
        """

        return NotificationService.send_user_notification(
            user_id=user_id,
            message="您的个人资料已成功更新",
            notification_type=type,
            data={
                "user_id": user_id,
                **profile_data,
                "updated_at": current_app.config['CURTIME']
            },
            level="success"
        )
    
    @classmethod
    def send_to_all_online_users(cls, message, notification_type='system', data=None, level='info'):
        """
        向所有在线用户发送通知（使用异步队列）
        
        Args:
            message: 通知消息内容
            notification_type: 通知类型
            data: 附加数据
            level: 通知级别 (info, success, warning, error)
        
        Returns:
            dict: 包含任务信息的结果
        """
        try:
            # 构建消息内容
            payload = {
                "message": message,
                "type": notification_type,
                "level": level
            }
            
            if data:
                payload["data"] = data
                
            # 获取所有用户通道
            user_channels = MemorySSE.get_user_channels()
            
            if not user_channels:
                current_app.logger.warning("没有找到活跃的用户通道，通知未发送")
                return {"queued": 0, "total": 0, "status": "no_channels"}
            
            # 确保工作线程正在运行
            cls._ensure_worker_running()
            
            # 将通知任务放入队列
            for channel in user_channels:
                cls._task_queue.put((channel, payload, 'notification'))
            
            current_app.logger.info(f"已将通知加入队列，准备发送给 {len(user_channels)} 个用户通道")
            return {
                "queued": len(user_channels), 
                "total": len(user_channels), 
                "status": "queued",
                "queue_size": cls._task_queue.qsize()
            }
            
        except Exception as e:
            current_app.logger.error(f"向所有在线用户发送通知失败: {str(e)}")
            return {"queued": 0, "total": 0, "status": "error", "error": str(e)}

    @staticmethod
    def send_site_sse(sitedata):
        """
        发送站点更新通知，发送给所有在线用户
        
        Args:
            sitedata: 更新的站点数据
        """
        return NotificationService.send_to_all_online_users(
            message="站点数据已更新",
            notification_type="system_config",  # 使用合适的类型名称
            data=sitedata,
            level="info"
        )
    
    @classmethod
    def shutdown(cls):
        """关闭通知工作线程（应用关闭时调用）；注意在Flask应用初始化时要先注册关闭函数"""
        with cls._worker_lock:
            if cls._is_worker_running:
                try:
                    # 发送退出信号
                    cls._task_queue.put(None)
                    # 等待工作线程结束
                    if cls._worker_thread and cls._worker_thread.is_alive():
                        cls._worker_thread.join(timeout=2)
                    cls._is_worker_running = False
                except:
                    pass

